import com.Ostermiller.util.LabeledCSVParser
import com.Ostermiller.util.CSVParser


/*
 * Reads the organization files
 **/
class OrgBPReader
{
    // the organization
    def Organization org;
    def orgServices =  new LinkedHashMap()
    def bFunctions =  new LinkedHashMap()
    def bProcesses =  new LinkedHashMap()
    def subProcesses =  new LinkedHashMap()
    def appServices =  new LinkedHashMap()
    def Logger logger = new Logger()

    def OrgBPReader(orgName)
    {
        this.org = new Organization(orgName)
    }

    def setLogger(logger)
    {
        // override the default stdout logger for this class
        this.logger = logger
    }

    /**
     * Reading Business Process and its timeline column items
     */
    def readBusinessProcess(lcsvp)
    {
        def bProcess
        
        // business process
        // populate the timeline for each business process
        def bProcessName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Business Process"))
        bProcess = new BusinessProcess(bProcessName)

        // start day and time
        bProcess.timelineItem.startDayOffset = Utils.readODStr(lcsvp.getValueByLabel("Start Day"))
        def int[] arrint = Utils.readTimeStr(lcsvp.getValueByLabel("Start Time"))

        bProcess.timelineItem.startDayHour = arrint[0]
        bProcess.timelineItem.startDayMins = arrint[1]

        // end day and time
        bProcess.timelineItem.endDayOffset = Utils.readODStr(lcsvp.getValueByLabel("End Day"))
        arrint = Utils.readTimeStr(lcsvp.getValueByLabel("End Time"))

        bProcess.timelineItem.endDayHour = arrint[0]
        bProcess.timelineItem.endDayMins = arrint[1]

        // isduration and isexact
        bProcess.timelineItem.isDuration = (lcsvp.getValueByLabel("Is Duration")!=null && lcsvp.getValueByLabel("Is Duration").equalsIgnoreCase("y"))?true:false;
        bProcess.timelineItem.isExact = (lcsvp.getValueByLabel("Is Exact")!=null && lcsvp.getValueByLabel("Is Exact").equalsIgnoreCase("y"))?true:false;

        return bProcess
    }


    /**
     * Reading Sub Process and its timeline column items
     */
    def readSubProcess(lcsvp)
    {
        def subProcess

        // business process
        // populate the timeline for each business process
        def subProcessName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Sub Process"))
        subProcess = new SubProcess(subProcessName)

        subProcess.initiator = Utils.readTrimmedStr(lcsvp.getValueByLabel("Initiator"))
        subProcess.role = Utils.readTrimmedStr(lcsvp.getValueByLabel("Role"))
        subProcess.frequency = Utils.readTrimmedStr(lcsvp.getValueByLabel("Frequency"))
        subProcess.trigger = Utils.readTrimmedStr(lcsvp.getValueByLabel("Trigger"))

        // start day and time
        subProcess.timelineItem.startDayOffset = Utils.readODStr(lcsvp.getValueByLabel("Start Day"))
        def int[] arrint = Utils.readTimeStr(lcsvp.getValueByLabel("Start Time"))

        subProcess.timelineItem.startDayHour = arrint[0]
        subProcess.timelineItem.startDayMins = arrint[1]

        // end day and time
        subProcess.timelineItem.endDayOffset = Utils.readODStr(lcsvp.getValueByLabel("End Day"))
        arrint = Utils.readTimeStr(lcsvp.getValueByLabel("End Time"))

        subProcess.timelineItem.endDayHour = arrint[0]
        subProcess.timelineItem.endDayMins = arrint[1]

        // isduration and isexact
        subProcess.timelineItem.isDuration = (lcsvp.getValueByLabel("Is Duration")!=null && lcsvp.getValueByLabel("Is Duration").equalsIgnoreCase("y"))?true:false;
        subProcess.timelineItem.isExact = (!lcsvp.getValueByLabel("Is Exact")!=null && lcsvp.getValueByLabel("Is Exact").equalsIgnoreCase("y"))?true:false;

        return subProcess
    }
    
    /**
    * Reads the Business Process Timeline for the organization
    * // Header Labels: Org Service,Business Function,Business Process,Start Day,Start Time,IsDuration,IsExact,End Day,End Time
    */
    void readBPTimeline(String fileName)
    {
        def timeLineCSVContents = inputFileToString(fileName)
        CSVParser csvParser = new CSVParser(new StringReader(timeLineCSVContents))
        LabeledCSVParser lcsvp = new LabeledCSVParser(csvParser);

        def orgService, bFunction, bProcess

        def ctr = 2
        logger.info("Business Processes:")

        // read each line of the CSV file and create objects
        while(lcsvp.getLine() != null)
        {
            logger.debug("ROW:" + ctr)

            def orgServiceName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Org Service"))

            // org-level service name
            if(orgServices[orgServiceName]==null)
            {
                orgService = new OrgService(orgServiceName)
                orgServices.put(orgServiceName, orgService)

                org.orgServices.put(orgServiceName, orgService)
            }

            // business function
            def bFunctionName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Business Function"))

            if(bFunctions[bFunctionName]==null)
            {
                bFunction = new BusinessFunction(bFunctionName)
                bFunctions.put(bFunctionName, bFunction)
                orgService.businessFunctions.put(bFunctionName, bFunction)
            }

            // business process            
            bProcess = readBusinessProcess(lcsvp)

            logger.info("\t|--" + ctr + "." + bProcess.name)

            bProcesses.put(bProcess.name, bProcess)
            bFunction.businessProcesses.put(bProcess.name, bProcess)
            
            ctr++
        }   // end - while  
    }


    /**
     * Read in the Sub processes
     */
    def readSubProcessTimeline(String fileName)
    {
        def timeLineCSVContents = inputFileToString(fileName)
        CSVParser csvParser = new CSVParser(new StringReader(timeLineCSVContents))
        LabeledCSVParser lcsvp = new LabeledCSVParser(csvParser);

        //println bProcesses["Create  DAM related Bill Determinants and Credit Determinants - OD + 1 0700 - OD + 1 1600"]
        // print each line
        def ctr = 2
        logger.info("SubProcesses:")
        while(lcsvp.getLine() != null)
        {
            def bProcessName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Business Process"))
            def bProcess = this.bProcesses[bProcessName]

            if(bProcess != null)
            {
                // reading the name
                //println "adding "+subProcessName+" bp:"+bProcessName

                def subProcess = readSubProcess(lcsvp)
                logger.info("\t|--" + ctr + "." + subProcess.name) //+ "-" + lcsvp.getLine()

                //println subProcess.name +" "+ subProcess.timelineItem
                this.subProcesses.put(subProcess.name, subProcess)
                bProcess.subProcesses.put(subProcess.name, subProcess)
            }
            else
            {
                logger.error("ERROR: in ROW:"+ctr+": Business Process not found: " + bProcessName)
                logger.info("ERROR: " + bProcessName + "- NOT FOUND!!!")
            }

            ctr++
        }
    }


    /**
     * Read the App Services
     */
    def readAppServices(String fileName)
    {
        def timeLineCSVContents = inputFileToString(fileName)
        CSVParser csvParser = new CSVParser(new StringReader(timeLineCSVContents))
        LabeledCSVParser lcsvp = new LabeledCSVParser(csvParser);
        
        def subProcess
        def ctr = 2
        logger.info("AppServices:") //+ "-" + lcsvp.getLine()

        while(lcsvp.getLine() != null)
        {
            def appService = new AppService()
            def subProcessName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Sub Process"))

            //logger.info("\t|--" + ctr + "." + subProcessName) //+ "-" + lcsvp.getLine()

            subProcess = this.subProcesses[subProcessName]

            if(subProcess != null)
            {
                appService.name = Utils.readTrimmedStr(lcsvp.getValueByLabel("App Service"))
                logger.info("\t|--" + ctr + "." + appService.name) //+ "-" + lcsvp.getLine()

                appService.abbrName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Abbreviated Name"))
                appService.sequenceNumber = Utils.readTrimmedStr(lcsvp.getValueByLabel("Sequence #"))!=null?java.lang.Integer.parseInt(Utils.readTrimmedStr(lcsvp.getValueByLabel("Sequence #"))):0
                appService.description = Utils.readTrimmedStr(lcsvp.getValueByLabel("Description"))
                def temp = Utils.readTrimmedStr(lcsvp.getValueByLabel("Context Tags"))

                if(temp!=null)
                    appService.contextTags = temp.split(",")

                appService.isExternal = Utils.readTrimmedStr(lcsvp.getValueByLabel("Internal or External")).equalsIgnoreCase("E")?true:false
                appService.sourceSystemName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Source System"))
                appService.sourceAppComponentName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Source App Component"))
                appService.dataObjectName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Data Object"))
                appService.dataObjectType = Utils.readTrimmedStr(lcsvp.getValueByLabel("Data Object Type"))
                appService.transactionSet = Utils.readTrimmedStr(lcsvp.getValueByLabel("Transaction Set")) // can have newlines but should not have
                appService.sinkSystemName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Sink System"))
                appService.sinkAppComponentName = Utils.readTrimmedStr(lcsvp.getValueByLabel("Sink App Component"))

                temp = Utils.readTrimmedStr(lcsvp.getValueByLabel("Sink DBTables")) // can have newlines but should not have
                if(temp!=null)
                    appService.sinkDBTables = temp.split(" ")

                this.appServices.put(appService.name, appService)
                subProcess.appServices.put(appService.name, appService)
            }
            else
            {
                logger.error("ERROR: in ROW:"+ctr+": Sub Process not found: " + subProcessName)
            }

            ctr++
        }
    }

    String inputFileToString(String fileName)
    {
        return new File(fileName).getText()
    }
}
